﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Mitosoft.Definitions.Services
{
  /// <summary>
  /// Service responsible to get directory information.
  /// </summary>
  public class DirectoryService : IDirectoryService
  {
    #region fields
    #endregion

    #region constructors

    /// <summary>
    /// Creates a new <see cref="DirectoryService"/> instance.
    /// </summary>
    // ReSharper disable once EmptyConstructor
    public DirectoryService()
    {
      // Intentionally left blank.
    }

    #endregion

    #region properties
    #endregion

    #region methods

    /// <summary>
    /// Gets the root directories.
    /// </summary>
    public List<string> RootDirectories
    {
      get
      {
        return 
          DriveInfo.GetDrives().Where(currentDriveInfo => currentDriveInfo.IsReady).ToList()
            .Select(currentDriveInfo => currentDriveInfo.RootDirectory.Name).ToList();
      }
    }

    /// <summary>
    /// Gets all top subdirectories of the given path.
    /// </summary>
    /// <param name="path">Represents the path of the directory we want to get the top subdirectories.</param>
    /// <returns>Found top sub directories or null if the given path is empty/null or it does not exist.</returns>
    public List<string> GetAllTopSubDirectories(string path)
    {
      return GetDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
    }

    /// <summary>
    /// Gets the directories of the given path.
    /// </summary>
    /// <param name="path">Starting path to get the contained directories.</param>
    /// <param name="searchPattern">Use "*.*" to select all files or use a custom pattern.</param>
    /// <param name="searchOption">Determines whether to select either recursively all directories or
    /// only the directories contained in the given path.</param>
    /// <returns>Found directories or null if the given path is empty/null or it does not exist.</returns>
    public List<string> GetDirectories(string path, string searchPattern, SearchOption searchOption)
    {
      if (string.IsNullOrEmpty(path)) return null;
      if (!Directory.Exists(path)) return null;

      try
      {
        string[] directories = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);

        List<string> result = directories.ToList();

        if (searchOption == SearchOption.TopDirectoryOnly)
          return result;

        var subDirectoriesResult = new List<string>();

        foreach (string currentDirectory in result)
        {
          List<string> subDirectories = GetDirectories(currentDirectory, searchPattern, searchOption);

          if (subDirectories != null) subDirectoriesResult.AddRange(subDirectories);
        }

        result.AddRange(subDirectoriesResult);
        return result;
      }
      
      // ReSharper disable EmptyGeneralCatchClause
      catch
      // ReSharper restore EmptyGeneralCatchClause
      {
        // Intentionally left blank
      }

      return null;
    }

    /// <summary>
    /// Gets the files belonging to the given directory.
    /// </summary>
    /// <param name="directoryPath">Path of the directory we want to know which files it contains.</param>
    /// <param name="searchPattern">Pattern used to filter the search results.</param>
    /// <returns>Found files or null if an error occured.</returns>
    public List<string> GetDirectoryFiles(string directoryPath, string searchPattern = "*.*")
    {
      try
      {
        if (string.IsNullOrEmpty(directoryPath)) return null;
        return Directory.GetFiles(directoryPath, searchPattern, SearchOption.TopDirectoryOnly).ToList();
      }
      catch (Exception)
      {
        return null;
      }
    }

    #endregion
  }
}
